﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.IO;
using System.Globalization;

namespace VehicleTrajectoryApp
{
    public class GPSLink
    {
        public double x1;
        public double y1;
        public double x2;
        public double y2;
        public DateTime start_time;
        public double segment_travel_time;

        public GPSLink(double x1, double y1, double x2, double y2, DateTime start_time, double segment_travel_time)
        {
            this.x1 = x1;
            this.y1 = y1;
            this.x2 = x2;
            this.y2 = y2;
            this.start_time = start_time;
            this.segment_travel_time = segment_travel_time;
        }
    }
    public class GPSTrajectory
    {
        public int TrajectoryID;
        public uint ProbeID;
        public double TrajectoryTimeInSecond;
        public double TrajectoryLength;
        public uint OriginAreaID;
        public uint DestinationAreaID;
        public DateTime TrajectoryStartTime;

        public GPSLink[] segmentArray;


        public GPSTrajectory(int trajID, uint probeID, double trajTimeInSeconds, double trajLength, uint o_ID, uint d_ID, DateTime trajStartTime)
        {
            this.TrajectoryID = trajID;
            this.ProbeID = probeID;
            this.TrajectoryTimeInSecond = trajTimeInSeconds;
            this.TrajectoryLength = trajLength;
            this.OriginAreaID = o_ID;
            this.DestinationAreaID = d_ID;
            this.TrajectoryStartTime = trajStartTime;
        }

        public static string AggregatedGPSTrajectoryFolder = @"D:\TestData\TomTom\AggregatedTrajectories";
        public static string DetailedGPSTrajectoryFolder = @"D:\TestData\TomTom\DetailedTrajectories";

        public static void ReadGPSTrajectoryFromTextFile(string gpsTrajectoryFileName, Dictionary<int,int> ZoneMap,ref Dictionary<ulong, Dictionary<int, List<GPSTrajectory>>> gpsTrajectoryMap)
        {
            string fullName = AggregatedGPSTrajectoryFolder + @"\" + gpsTrajectoryFileName;
            if (File.Exists(fullName))
            {
                using (StreamReader file = new StreamReader(fullName))
                {
                    string line = file.ReadLine();

                    string trajID;
                    int probeID;
                    double trajTimeInSeconds;
                    double trajLength;
                    int o_ID;
                    int d_ID;
                    DateTime trajStartTime;

                    int n = 0;
                    while ((line = file.ReadLine()) != null)
                    {
                        string[] subString = line.Split(',');

                        if (subString.Length == 7)
                        {
                            trajID = subString[0];
                            if (Int32.TryParse(subString[1], out probeID) && Double.TryParse(subString[2], out trajTimeInSeconds)
                                && Double.TryParse(subString[3], out trajLength)
                                && Int32.TryParse(subString[4], out o_ID)
                                && Int32.TryParse(subString[5], out d_ID)
                                //&& DateTime.TryParse(subString[6], out trajStartTime)
                                )
                            {
                                string dateFormat = "ddd MMM dd HH:mm:ss yyyy";
                                try
                                {
                                    trajStartTime = DateTime.ParseExact(subString[6], dateFormat, null);

                                    if (trajStartTime.DayOfWeek == DayOfWeek.Sunday
                                        || trajStartTime.DayOfWeek == DayOfWeek.Saturday
                                        || trajStartTime.TimeOfDay.Hours < 6
                                        || trajStartTime.TimeOfDay.Hours > 9
                                        )
                                    {
                                        continue;
                                    }

                                    GPSTrajectory gpsTrajectory = new GPSTrajectory(n, (uint)probeID, trajTimeInSeconds, trajLength, (uint)o_ID, (uint)d_ID, trajStartTime);
                                    n++;

                                    if (gpsTrajectoryMap == null)
                                    {
                                        gpsTrajectoryMap = new Dictionary<ulong, Dictionary<int, List<GPSTrajectory>>>();
                                    }

                                    //int mappedDSPFromID, mappedDSPToID;
                                    //if (ZoneMap.ContainsKey(o_ID) && ZoneMap.ContainsKey(d_ID))
                                    //{
                                    //    mappedDSPFromID = ZoneMap[o_ID];
                                    //    mappedDSPToID = ZoneMap[d_ID];
                                    //}
                                    //else
                                    //{
                                    //    continue;
                                    //}

                                    ulong key = (((ulong)o_ID) << 32) | (uint)d_ID;
                                    if (!gpsTrajectoryMap.ContainsKey(key))
                                    {
                                        gpsTrajectoryMap[key] = new Dictionary<int, List<GPSTrajectory>>();
                                    }

                                    int timeIndex = (int)(trajStartTime.Hour / 15);
                                    if (timeIndex > (9 - 6) * 4)
                                    {
                                        timeIndex = (9 - 6) * 4;
                                    }
                                    if (!gpsTrajectoryMap[key].ContainsKey(timeIndex))
                                    {
                                        gpsTrajectoryMap[key][timeIndex] = new List<GPSTrajectory>();
                                    }

                                    string detailedTrajectoryFolderName = System.IO.Path.GetFileNameWithoutExtension(gpsTrajectoryFileName);
                                    string detailedTrajectoryFullName = DetailedGPSTrajectoryFolder + @"\" + detailedTrajectoryFolderName + @"\" + trajID + ".csv";

                                    gpsTrajectory.segmentArray = ReadDetailedGPSTrajectorySegmentsFromFile(detailedTrajectoryFullName);
                                    gpsTrajectoryMap[key][timeIndex].Add(gpsTrajectory);                                  
                                }
                                catch (FormatException)
                                {
                                }
                            }
                        }

                    }
                }
            }
        }

        public static GPSLink[] ReadDetailedGPSTrajectorySegmentsFromFile(string detailedTrajectoryFileName)
        {
            List<GPSLink> segmentList = new List<GPSLink>();
            using (StreamReader reader = new StreamReader(detailedTrajectoryFileName))
            {
                string line = reader.ReadLine();

                while ((line = reader.ReadLine()) != null)
                {
                    string[] subString = line.Split(',');

                    double x1 = Double.Parse(subString[2]);
                    double y1 = Double.Parse(subString[3]);
                    double x2 = Double.Parse(subString[4]);
                    double y2 = Double.Parse(subString[5]);
                    double segment_travel_time = Double.Parse(subString[6]);

                    DateTime start_time;

                    string dateFormat = "ddd MMM dd HH:mm:ss yyyy";
                    try
                    {
                        start_time = DateTime.ParseExact(subString[9], dateFormat, null);

                        if (start_time.DayOfWeek == DayOfWeek.Sunday
                            || start_time.DayOfWeek == DayOfWeek.Saturday
                            || start_time.TimeOfDay.Hours < 6
                            || start_time.TimeOfDay.Hours > 9
                            )
                        {
                            continue;
                        }
                        else
                        {
                            segmentList.Add(new GPSLink(x1, y1, x2, y2, start_time, segment_travel_time));
                        }
                    }
                    catch (FormatException)
                    {
                    }
                }
            }

            if (segmentList.Count > 0)
            {
                return segmentList.ToArray();
            }
            else
            {
                return null;
            }
        }

        public static Dictionary<ulong, List<GPSTrajectory>> ReadGPSTrajectoryFromFile(string gpsTrajectoryFileName)
        {
            Dictionary<ulong, List<GPSTrajectory>> gpsTrajectoryMap = null;
            if (File.Exists(gpsTrajectoryFileName))
            {
                using (StreamReader file = new StreamReader(gpsTrajectoryFileName))
                {
                    string line = file.ReadLine();

                    string trajID;
                    int probeID;
                    double trajTimeInSeconds;
                    double trajLength;
                    int o_ID;
                    int d_ID;
                    DateTime trajStartTime;

                    while ((line = file.ReadLine()) != null)
                    {
                        string[] subString = line.Split(',');

                        if (subString.Length == 7)
                        {
                            trajID = subString[0];
                            if (Int32.TryParse(subString[1], out probeID) && Double.TryParse(subString[2], out trajTimeInSeconds)
                                && Double.TryParse(subString[3], out trajLength)
                                && Int32.TryParse(subString[4], out o_ID)
                                && Int32.TryParse(subString[5], out d_ID)
                                )
                            {
                                string dateFormat = "ddd MMM dd HH:mm:ss yyyy";
                                try
                                {
                                    trajStartTime = DateTime.ParseExact(subString[6], dateFormat, null);

                                    if (trajStartTime.DayOfWeek == DayOfWeek.Sunday 
                                        || trajStartTime.DayOfWeek == DayOfWeek.Saturday
                                        || trajStartTime.TimeOfDay.Hours < 6 
                                        || trajStartTime.TimeOfDay.Hours > 9
                                        )
                                    {
                                        continue;
                                    }

                                    GPSTrajectory gpsTrajectory = new GPSTrajectory(trajID, (uint)probeID, trajTimeInSeconds, trajLength, (uint)o_ID, (uint)d_ID, trajStartTime);
                                    if (gpsTrajectoryMap == null)
                                    {
                                        gpsTrajectoryMap = new Dictionary<ulong, List<GPSTrajectory>>();
                                    }

                                    ulong key = (((ulong)o_ID) << 32) | (uint)d_ID;
                                    if (gpsTrajectoryMap.ContainsKey(key))
                                    {
                                        gpsTrajectoryMap[key].Add(gpsTrajectory);
                                    }
                                    else
                                    {
                                        gpsTrajectoryMap[key] = new List<GPSTrajectory>();
                                        gpsTrajectoryMap[key].Add(gpsTrajectory);
                                    }
                                }
                                catch (FormatException)
                                {
                                }
                            }
                        }

                    }
                }
            }

            return gpsTrajectoryMap;
        }
    }
}
